#include "Geometry.h"
#include <iostream>

using namespace std;

Symbol parseTranslate(ifstream &file, Symbol curToken, mat4 *trans) {
    float *fillNum;

    fillNum = parseVector(file, curToken, &curToken, 3);

    *(trans) = translate(mat4(1.0f), 
            vec3(fillNum[0], fillNum[1], fillNum[2])) * (*trans);

    delete fillNum;
    return curToken;
}

Symbol parseRotate(ifstream &file, Symbol curToken, mat4 *trans) {
    float *fillNum;

    fillNum = parseVector(file, curToken, &curToken, 3);

    *(trans) = 
        rotate(mat4(1.0), fillNum[2], vec3(0.0f, 0.0f, 1.0f)) *
        rotate(mat4(1.0), fillNum[1], vec3(0.0f, 1.0f, 0.0f)) *
        rotate(mat4(1.0), fillNum[0], vec3(1.0f, 0.0f, 0.0f)) * (*trans);

    delete fillNum;
    return curToken;
}

Symbol parseScale(ifstream &file, Symbol curToken, mat4 *trans) {
    float *fillNum;
    
    fillNum = parseVector(file, curToken, &curToken, 3);

    *(trans) = scale(mat4(1.0), vec3(fillNum[0], fillNum[1], fillNum[2])) *
        (*trans);

    delete fillNum;
    return curToken;
}

Symbol parseMaterials(ifstream &file, Symbol curToken, Geometry *g) {
    while (curToken.t != RBrace) {
        if (curToken.t == Pigment) {
            curToken = g->pigment.parse(file, 
                matchToken(file, curToken, Pigment));
        }
        else if (curToken.t == Finish) {
            curToken = g->finish.parse(file,
                matchToken(file, curToken, Finish));
        }
        else if (curToken.t == Translate) {
            curToken = parseTranslate(file,
                matchToken(file, curToken, Translate), &(g->transform));
        }
        else if (curToken.t == Rotate) {
            curToken = parseRotate(file,
                matchToken(file, curToken, Rotate), &(g->transform));
        }
        else if (curToken.t == Scale) {
            curToken = parseScale(file,
                matchToken(file, curToken, Scale), &(g->transform));
        }
        else {
            /*if (curToken.isToken)
                cout << tokenList[curToken.t] << endl;
            else cout << curToken.num << endl;
            curToken = nextToken(file);*/
            cout << "Unexpected token: " << tokenList[curToken.t] << endl;
            exit(1);
        }
    }

    g->vtrans = g->transform;
    g->transform = inverse(g->transform);

    return matchToken(file, curToken, RBrace);
}

vec3 min_vec(vec4 *arr, int num) {
    vec3 ret;
    int i = 1;

    ret = vec3(arr[0].x, arr[0].y, arr[0].z);

    while (i < num) {
        if (ret.x > arr[i].x)
            ret.x = arr[i].x;

        if (ret.y > arr[i].y)
            ret.y = arr[i].y;

        if (ret.z > arr[i].z)
            ret.z = arr[i].z;

        i++;
    }

    return ret;
}

vec3 max_vec(vec4 *arr, int num) {
    vec3 ret;
    int i = 1;

    ret = vec3(arr[0]);

    while (i < num) {
        if (ret.x < arr[i].x)
            ret.x = arr[i].x;

        if (ret.y < arr[i].y)
            ret.y = arr[i].y;

        if (ret.z < arr[i].z)
            ret.z = arr[i].z;

        i++;
    }

    return ret;
}

void fix_AABB_transform(AABB *b, mat4 vtrans) {
    vec4 arr[8];

    arr[0] = vec4(b->min.x, b->min.y, b->min.z, 1.0);
    arr[0] = vtrans * arr[0];

    arr[1] = vec4(b->max.x, b->max.y, b->max.z, 1.0);
    arr[1] = vtrans * arr[1];

    arr[2] = vec4(b->min.x, b->min.y, b->max.z, 1.0);
    arr[2] = vtrans * arr[2];

    arr[3] = vec4(b->min.x, b->max.y, b->min.z, 1.0);
    arr[3] = vtrans * arr[3];

    arr[4] = vec4(b->max.x, b->min.y, b->min.z, 1.0);
    arr[4] = vtrans * arr[4];

    arr[5] = vec4(b->min.x, b->max.y, b->max.z, 1.0);
    arr[5] = vtrans * arr[5];

    arr[6] = vec4(b->max.x, b->min.y, b->max.z, 1.0);
    arr[6] = vtrans * arr[6];

    arr[7] = vec4(b->max.x, b->max.y, b->min.z, 1.0);
    arr[7] = vtrans * arr[7];

    b->min = min_vec(arr, 8);
    b->max = max_vec(arr, 8);
}
